//
// Created by martin on 3/24/22.
//

#include "HttpContext.h"
#include "muduo/net/Buffer.h"

using namespace muduo;
using namespace muduo::net;

// request false if any error
bool HttpContext::parseRequest(Buffer *buf, Timestamp receiveTime)
{
    bool ok = true;
    bool hasMore = true;
    while (hasMore)
    {
        switch (state_)
        {
            case kExpectRequestLine:
            {
                const char* crlf = buf->findCRLF();
                if (crlf)
                {
                    ok = processRequestLine(buf->peek(), crlf);
                    if (ok)
                    {
                        request_.setReceiveTime(receiveTime);
                        buf->retrieveUntil(crlf + 2);
                        state_ = kExpectHeaders;
                    }
                    else
                    {
                        hasMore = false;
                    }
                }
                else
                {
                    hasMore = false;
                }
            }
            break;

            case kExpectHeaders:
            {
                const char* crlf = buf->findCRLF();
                if (crlf)
                {
                    const char* colon = std::find(buf->peek(), crlf, ':');
                    if (colon != crlf)
                    {
                        request_.addHeader(buf->peek(), colon, crlf);
                    }
                    else
                    { // empty line, end of header
                        state_ = kGotAll;
                        hasMore = false;
                    }
                    buf->retrieveUntil(crlf + 2);
                }
                else
                {
                    hasMore = false;
                }
            }
            break;

            case kExpectBody:
            {
                // FIXME:
            }
            break;

#if 0
            case kGotAll:
            break;
#endif
            default:
                hasMore = false;
                break;
        }
    }
    return ok;
}

bool HttpContext::processRequestLine(const char *begin, const char *end)
{
    bool succeed = false;
    const char* start = begin;
    const char* space = std::find(start, end, ' ');
    if (space != end && request_.setMethod(start, space))
    {
        start = space + 1;
        space = std::find(start, end, ' ');
        if (space != end)
        {
            const char* question = std::find(start, space, '?');
            if (question != space)
            {
                request_.setPath(start, question);
                request_.setQuery(question, space);
            }
            else
            {
                request_.setPath(start, space);
            }
            start = space + 1;
            succeed = end - start == 8 && std::equal(start, end - 1, "HTTP/1.");
            if (succeed)
            {
                if (*(end - 1) == '1')
                { // HTTP/1.1
                    request_.setVersion(HttpRequest::kHttp11);
                }
                else if (*(end - 1) == '0')
                { // HTTP/1.0
                    request_.setVersion(HttpRequest::kHttp10);
                }
                else
                {
                    succeed = false;
                }
            }
        }
    }
    return succeed;
}
